package com.jyxd.web.service.patient;

import com.jyxd.web.dao.basic.BedArrangeDao;
import com.jyxd.web.dao.dictionary.DepartmentDictionaryDao;
import com.jyxd.web.dao.dictionary.MonitorDictionaryDao;
import com.jyxd.web.dao.patient.PatientDao;
import com.jyxd.web.dao.patient.PatientDiagnosisDao;
import com.jyxd.web.dao.user.UserDao;
import com.jyxd.web.data.basic.BedArrange;
import com.jyxd.web.data.dictionary.MonitorDictionary;
import com.jyxd.web.data.dto.HttpResult;
import com.jyxd.web.data.patient.Patient;
import com.jyxd.web.data.patient.PatientDiagnosis;
import com.jyxd.web.data.user.User;
import com.jyxd.web.util.DateUtil;
import com.jyxd.web.util.FileUtil;
import com.jyxd.web.util.SliceUpDateUtil;
import com.jyxd.web.util.UUIDUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

import static com.jyxd.web.config.ConstantConfig.PATIENT_EXCHANGE_CODE_BE_HOSPITALIZED;
import static com.jyxd.web.util.ExecuteUtil.errorIfEmpty;
import static com.jyxd.web.util.Ping.ping;

@Service("patientService")
@Transactional
public class PatientService {

    private static Logger logger = LoggerFactory.getLogger(PatientService.class);

    @Autowired
    private PatientDao patientDao;


    @Autowired
    private DepartmentDictionaryDao departmentDictionaryDao;

    @Autowired
    private PatientDiagnosisDao patientDiagnosisDao;

    @Autowired
    private BedArrangeDao bedArrangeDao;

    @Autowired
    private MonitorDictionaryDao monitorDictionaryDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private PatientExchangeRecordService patientExchangeRecordService;

    @Autowired
    private PatientDiagnosisService patientDiagnosisService;

    public boolean insert(Patient patient, Boolean isHIs) {
        // 患者新增时为患者入院/入科信息 新增患者流转记录入院信息
        patientExchangeRecordService.addPatientExchangeRecord(PATIENT_EXCHANGE_CODE_BE_HOSPITALIZED, "患者入院/入科，床位号为：" + patient.getBedCode(), patient.getId());

        if (!isHIs) {
            if (StringUtils.isNotEmpty(patient.getDepartmentCode()) && StringUtils.equalsAny(patient.getDepartmentCode(), "神经内科", "重症医学科")) {
                patient.setFlag(1);
                // 重症 status=1 神经内科 status =2
                patient.setStatus(StringUtils.equals(patient.getDepartmentCode(), "重症医学科") ? 1 : 2);
            } else {
                patient.setStatus(-1);
                patient.setFlag(0);
            }
            //存入患者诊断表
            if(StringUtils.isNotBlank(patient.getDiagnosisName())){
                PatientDiagnosis patientDiagnosis = new PatientDiagnosis();
                patientDiagnosis.setId(UUIDUtil.getUUID());
                patientDiagnosis.setCreateTime(new Date());
                patientDiagnosis.setPatientId(patient.getId());
                patientDiagnosis.setDiagnosisName(patient.getDiagnosisName());
                patientDiagnosisService.insert(patientDiagnosis);
            }
        }
        patient.setVisitId(patient.getVisitId());
        patient.setAppId(patient.getAppId());

        return patientDao.insert(patient);
    }

    public boolean update(Patient patient) {
        logger.info(DateUtil.yyyyMMddHHmmssSdfToString(new Date())+"更新患者信息"+patient.toString());
        return patientDao.update(patient);
    }

    public Patient queryData(String id) {
        return patientDao.queryData(id);
    }

    public List<Patient> queryList(Map<String, Object> map) {
        return patientDao.queryList(map);
    }

    public List<Patient> queryOtherList(Map<String, Object> map) {
        return patientDao.queryOtherList(map);
    }

    public int queryOtherNum(Map<String, Object> map) {
        return patientDao.queryOtherNum(map);
    }

    public int queryNum(Map<String, Object> map) {
        return patientDao.queryNum(map);
    }

    public List<Map<String, Object>> getList(Map<String, Object> map) {
        return patientDao.getList(map);
    }

    public int getNum(Map<String, Object> map) {
        return patientDao.getNum(map);
    }

    public int getAllNum() {
        return patientDao.getAllNum();
    }

    public List<LinkedHashMap<String, Object>> getDownloadList(Map<String, Object> map) {
        return patientDao.getDownloadList(map);
    }

    public void getExcel(HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<>();
        List<LinkedHashMap<String, Object>> withdrawVos = patientDao.getDownloadList(map);

        // 创建工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 创建表
        HSSFSheet sheet = workbook.createSheet("病人信息");
        // 创建行
        HSSFRow row = sheet.createRow(0);
        // 创建单元格样式
        HSSFCellStyle cellStyle = workbook.createCellStyle();
        // 表头
        String[] head = {"住院号", "姓名", "性别", "入科时间", "出科时间", "当前状态", "出科方式", "来源科室", "去向科室", "入科床号", "住院时间",
                "是否非计划", "病情", "责任医生", "责任护士", "最新手术时间", "最新手术名称", "诊断", "过敏史", "阳性"};
        HSSFCell cell;
        // 设置表头
        for (int iHead = 0; iHead < head.length; iHead++) {
            cell = row.createCell(iHead);
            cell.setCellValue(head[iHead]);
            cell.setCellStyle(cellStyle);
        }
        // 设置表格内容
        for (int iBody = 0; iBody < withdrawVos.size(); iBody++) {
            row = sheet.createRow(iBody + 1);
            LinkedHashMap<String, Object> u = withdrawVos.get(iBody);
            String[] userArray = new String[20];
            userArray[0] = u.get("住院号").toString();
            userArray[1] = u.get("姓名").toString();
            userArray[2] = u.get("性别").toString();
            userArray[3] = u.get("入科时间").toString();
            userArray[4] = u.get("出科时间").toString();
            userArray[5] = u.get("当前状态").toString();
            userArray[6] = u.get("出科方式").toString();
            userArray[7] = u.get("来源科室").toString();
            userArray[8] = u.get("去向科室").toString();
            userArray[9] = u.get("入科床号").toString();
            userArray[10] = u.get("住院时间").toString();
            userArray[11] = u.get("是否非计划").toString();
            userArray[12] = u.get("病情").toString();
            userArray[13] = u.get("责任医生").toString();
            userArray[14] = u.get("责任护士").toString();
            userArray[15] = u.get("最新手术时间").toString();
            userArray[16] = u.get("最新手术名称").toString();
            userArray[17] = u.get("诊断").toString();
            userArray[18] = u.get("过敏史").toString();
            userArray[19] = u.get("阳性").toString();
            for (int iArray = 0; iArray < userArray.length; iArray++) {
                row.createCell(iArray).setCellValue(userArray[iArray]);
            }
        }
        // 生成Excel文件
        FileUtil.createFile(response, workbook);
    }

    public int getNowPatientNum(Map<String, Object> map) {
        return patientDao.getNowPatientNum(map);
    }

    /**
     * 首页查询在科病人来源
     *
     * @return
     */
    public JSONArray getPatientSource(Map<String, Object> map) {
        JSONArray array = new JSONArray();
        List<Map<String, Long>> result = patientDao.statisticsPatientSource(map);
        for (Map<String, Long> objectMap : result) {
            JSONObject obj = new JSONObject();
            Long value = objectMap.get("num");
            if (value > 0) {
                obj.put("value",value);
                obj.put("name",objectMap.get("department"));
                array.add(obj);
            }
        }
        return array;
    }

    /**
     * 首页查询床位列表
     *
     * @return
     */
    public List<Map<String, Object>> getBedPatientList(Map<String,Object> map) {
        return patientDao.getBedPatientList(map);
    }

    public List<Map<String, Object>> getPatientDiagnosisName(Map<String,Object> map) {
        List<Map<String, Object>> bedPatientList = getBedPatientList(map);
        return bedPatientList;
    }

    /**
     * 赋值患者诊断数据
     *
     * @param patientList
     * @return
     */
    private List<Map<String, Object>> setDiagnosisName(List<Map<String, Object>> patientList, String id) {
        if (CollectionUtils.isEmpty(patientList)) {
            return null;
        }
        for (Map<String, Object> patientMap : patientList) {
            if (StringUtils.isNotEmpty((String) patientMap.get("diagnosis_name"))) {
                continue;
            }
            if (StringUtils.isEmpty((String) patientMap.get(id))) {
                continue;
            }
            String patientId = (String) patientMap.get(id);
            PatientDiagnosis patientDiagnosis = patientDiagnosisDao.queryDataByPatientId(patientId);
            if (Objects.isNull(patientDiagnosis)) {
                continue;
            }
            patientMap.put("diagnosis_name", patientDiagnosis.getDiagnosisName());
        }
        return patientList;
    }

    /**
     * 查询待分配的病人列表（是否分配床位）
     *
     * @param map
     * @return
     */
    public List<Patient> getNoBedPatientList(Map<String, Object> map) {
        return patientDao.getNoBedPatientList(map);
    }

    /**
     * 查询已出科的病人列表
     *
     * @param map
     * @return
     */
    public List<Patient> getOutPatientList(Map<String, Object> map) {
        return patientDao.getOutPatientList(map);
    }

    /**
     * 统计分析--出入科--转入转出分析
     *
     * @param map
     * @return
     */
    public int getOutAndIn(Map<String, Object> map) {
        return patientDao.getOutAndIn(map);
    }

    /**
     * 查询所有病人的入科科室分类名称
     *
     * @return
     */
    public List<Map<String, Object>> getAllEnterDepartment(Map<String, Object> map) {
        return patientDao.getAllEnterDepartment(map);
    }

    /**
     * 统计分析--出入科--转入或转出科室病人数量
     *
     * @param map
     * @return
     */
    public int getEnterAndExitDepartment(Map<String, Object> map) {
        return patientDao.getEnterAndExitDepartment(map);
    }

    /**
     * 查询所有病人的出科科室分类名称
     *
     * @return
     */
    public List<Map<String, Object>> getAllExitDepartment(Map<String, Object> map) {
        return patientDao.getAllExitDepartment(map);
    }

    /**
     * 统计分析--出入科--趋势分析--转出方式
     *
     * @return
     */
    public List<Map<String, Object>> getNumByExitType(Map<String, Object> map) {
        return patientDao.getNumByExitType(map);
    }

    /**
     * 统计分析--出入科--趋势分析--转出方式（按月）
     *
     * @return
     */
    public List<Map<String, Object>> getNumByExitTypeMonth(Map<String, Object> map) {
        return patientDao.getNumByExitTypeMonth(map);
    }

    /**
     * 模拟查询视图
     *
     * @return
     */
    public List<Map<String, Object>> queryListTest(Map<String, Object> map) {
        return null;
    }

    /**
     * 查询所有病人信息 stats!=-1
     *
     * @return
     */
    public List<Patient> queryPatientList(Map<String, Object> map) {
        return patientDao.queryPatientList(map);
    }

    /**
     * 从his系统视图查询所有病人信息
     *
     * @return
     */
    public List<Map<String, Object>> getPatientByHis(Map<String, Object> map) {
        return null;
    }

    /**
     * 根据条件查询病人对象
     *
     * @param map
     * @return
     */
    public Patient getPatientByConditions(Map<String, Object> map) {
        return patientDao.getPatientByConditions(map);
    }

    /**
     * 从his系统视图查询所有病人转移信息
     *
     * @return
     */
    public List<Map<String, Object>> getTransferByHis(Map<String, Object> map) {
        return null;
    }

    /**
     * 病人管理--首页--查询病人监护仪及采集频率
     *
     * @param map
     * @return
     */
    public Map<String, Object> queryPatientMonitor(Map<String, Object> map) {
        return patientDao.queryPatientMonitor(map);
    }

    Patient getPatientByDocumentNoAndFlagAndStatus(String documentNo, String flag, String status) {
        return patientDao.getPatientByDocumentNoAndFlagAndStatus(documentNo, flag, status);
    }

    /**
     * 根据患者主索引号查询最近的一条病人记录
     *
     * @param visitId
     * @return
     */
    public Patient getPatientByVisitId(String visitId) {
        return patientDao.getPatientByVisitId(visitId);
    }

    /**
     * 根据患者主索引号查询最近的一条病人记录
     *
     * @param visitId
     * @return
     */
    public Patient getPatientByVisitIdAndFlagAndStatus(String visitId, String flag, String status) {
        return patientDao.getPatientByVisitIdAndFlagAndStatus(visitId, flag, status);
    }

    /**
     * 通过当前时间查询现有患者
     *
     * @param map
     * @return
     */
    public Map<String, Object> getExitpatientNum(Map<String, Object> map) {
        Map<String, Object> listMap = new HashMap<String, Object>();
        List<String> datetimeList = new ArrayList<>();
        List<Integer> exitpatientNumList = new ArrayList<Integer>();
        List<Integer> transferPatientNumList = new ArrayList<Integer>();
        List<Integer> rollOutPatientNumList = new ArrayList<Integer>();

        int status = 0;
        if(map.containsKey("status")){
            status = Integer.valueOf(map.get("status").toString());
        }
        if (map.get("type").toString().equals("按天")) {
            String startTime = map.get("startTime").toString();
            String endTime = map.get("endTime").toString();
            datetimeList = SliceUpDateUtil.sliceUpDateRange(startTime, endTime, 3);
            //现有患者 判断 flag=1   且enter_time<=当前时间的
            //转入患者  判断flag=1  且enter_time =查询时间
            //转出患者  判断flag=0  且exit_time =查询时间
            for (String datatime : datetimeList) {
                int num = patientDao.getExitPatientNumMultiDept(datatime, "day",status);
                int num2 = patientDao.getTransferPatientNumMultiDept(datatime, "day",status);
                int num3 = patientDao.getRollOutPatientNumMultiDept(datatime, "day", null,status);
                exitpatientNumList.add(num);
                transferPatientNumList.add(num2);
                rollOutPatientNumList.add(num3);
            }

        } else if (map.get("type").toString().equals("按月")) {
            String year = (String) map.get("year");
            datetimeList = SliceUpDateUtil.sliceUpDateRange(year + "-01", year + "-12", 2);
            for (String datatime : datetimeList) {
                int num = patientDao.getExitPatientNumMultiDept(datatime, "month",status);
                int num2 = patientDao.getTransferPatientNumMultiDept(datatime, "month",status);
                int num3 = patientDao.getRollOutPatientNumMultiDept(datatime, "month", null,status);
                exitpatientNumList.add(num);
                transferPatientNumList.add(num2);
                rollOutPatientNumList.add(num3);
            }

        }
        listMap.put("datetimeList", datetimeList);
        listMap.put("exitpatientNumList", exitpatientNumList);
        listMap.put("transferPatientNumList", transferPatientNumList);
        listMap.put("rollOutPatientNumList", rollOutPatientNumList);
        return listMap;
    }


    /**
     * 查询所有在床且在科的病人
     *
     * @return
     */
    public List<Patient> queryPatientByFlagAndBed(String status) {
        return patientDao.queryPatientByFlagAndBed(status);
    }

    /**
     * 修改脉搏频率记录状态
     *
     * @param map
     * @return
     */
    public HttpResult openPulseRecord(Map<String, Object> map) {
        if (CollectionUtils.isEmpty(map)) {
            return new HttpResult(500, "参数不存在");
        }
        if (Objects.isNull(map.get("patientId"))) {
            return new HttpResult(500, "患者id不存在");
        }
        if (Objects.isNull(map.get("openStatus"))) {
            return new HttpResult(500, "开关状态不存在");
        }
        String patientId = String.valueOf(map.get("patientId"));
        String openStatus = String.valueOf(map.get("openStatus"));
        Patient patient = patientDao.queryData(patientId);
        if (Objects.isNull(patient)) {
            return new HttpResult(500, "患者不存在");
        }
        patient.setIsOpenPulseRecord(openStatus);
        if (patientDao.update(patient)) {
            return new HttpResult(200, "状态修改成功");
        }
        return new HttpResult(500, "状态修改失败");
    }

    /**
     * 查询获取拼接360查询url
     *
     * @param map
     * @return
     */
    public HttpResult get360ViewUrl(Map<String, Object> map) {
        try {
            errorIfEmpty(map, "参数不能为空");
            errorIfEmpty(map.get("visitId"), "患者住院号不能为空");
            errorIfEmpty(map.get("userWorkNumber"), "医生工号不能为空");
            String visitId = (String) map.get("visitId");
            String userWorkNumber = (String) map.get("userWorkNumber");
            Map<String, Object> userMap = new HashMap<>();
            userMap.put("workNumber", userWorkNumber);
            User user = userDao.queryDataByWorkNumber(userMap);
            errorIfEmpty(user.getAppId(), "医生第三方id不存在");
            errorIfEmpty(user.getDeptCode(), "医生所属科室不存在，无法查询360系统");
            errorIfEmpty(user, "查询医生工号不存在");
            Patient patient = getPatientByVisitId(visitId);
            errorIfEmpty(patient, "患者不存在");
            errorIfEmpty(patient.getAppId(), "第三方患者id不存在");
            errorIfEmpty(patient.getVisitId(), "第三方患者就诊流水号不存在");
            StringBuffer url = new StringBuffer();
            url.append("http://172.21.101.166:8080/winsso/c");
            url.append("/").append(user.getAppId()); // 医生工号
            // 患者身份证号
            if (Objects.nonNull(patient.getIdCard()))
                url.append("/").append(patient.getIdCard());
            else
                url.append("/").append("0");
            url.append("/").append("2"); // 就诊类别
            url.append("/").append(patient.getAppId()); // his患者id
            url.append("/").append(patient.getVisitId()); // his患者就诊流水号
            url.append("/0").append("/0");   // 患者医保卡号和患者院内卡号，没有则默认传0
            url.append("/").append(patient.getAppId()); // 患者病历号与患者第三方id一致
            url.append("/").append("-1"); // 模块号（his固定）
            url.append("/").append("40570021614040211A1001"); // 医疗机构代码（his固定）
            url.append("/").append("0");  // 婴儿序号（大人为0，婴儿为大于0的自然数）
            url.append("/").append(user.getDeptCode());
            url.append("/").append("zzjhclient"); // 客户端编号（his固定）
            return new HttpResult(200, url.toString(), "请求地址查询成功");
        } catch (Exception e) {
            e.printStackTrace();
            return new HttpResult(500, e.getMessage());
        }
    }

    /**
     * 首页空床位列表
     *
     * @return
     */
    public List<Map<String, Object>> getBedNullPatientList(Map<String,Object> map) {
        return patientDao.getBedNullPatientList(map);
    }


    /**
     * 检测监护仪ip是否断开
     *
     * @return
     */
    public HttpResult testMonitorIp(Map<String, Object> map) {
        try {
            errorIfEmpty(CollectionUtils.isEmpty(map), "查询条件不能为空");
            errorIfEmpty(Objects.isNull(map.get("bedCode")), "床位号参数不存在");
            BedArrange bedArrange = bedArrangeDao.queryDataByBedCode(map);
            errorIfEmpty(bedArrange, "床位关联信息为空");
            errorIfEmpty(bedArrange.getMonitorCode(), "床位关联监护仪不存在");
            MonitorDictionary monitor = monitorDictionaryDao.getMonitorByMonitorCode(bedArrange.getMonitorCode(), String.valueOf(map.get("tenantId")));
            errorIfEmpty(monitor, "监护仪数据不存在");
            errorIfEmpty(monitor.getMonitorIp(), "监护仪ip地址未设置");
            String message = ping(monitor.getMonitorIp()) ? "监护仪网络正常" : "监护仪网络连接错误";
            return new HttpResult(200, message);
        } catch (Exception e) {
            return new HttpResult(500, e.getMessage());
        }
    }

    public HttpResult updateSyncNewOrOldVitalSign(Map<String, Object> map) {
        errorIfEmpty(map, "参数不能为空");
        errorIfEmpty(map.get("patientId"), "患者id不能为空");
        errorIfEmpty(map.get("syncNewOrOldVitalSign"), "患者标识内容不能为空");
        String syncNewOrOldVitalSign = (String) map.get("syncNewOrOldVitalSign");
        if (!StringUtils.equals(syncNewOrOldVitalSign, "true") && !StringUtils.equals(syncNewOrOldVitalSign, "false"))
            return new HttpResult(500, "标识状态错误");
        Patient patient = queryData((String) map.get("patientId"));
        errorIfEmpty(patient, "患者不存在");
        patient.setSyncNewOrOldVitalSign(syncNewOrOldVitalSign);
        update(patient);
        return new HttpResult(200, "患者新旧表单标识修改成功");
    }

    public HttpResult batchUpdateSyncNewOrOldVitalSign(Map<String, Object> map) {
        errorIfEmpty(map, "参数不能为空");
        errorIfEmpty(map.get("visitTime"), "患者id不能为空");
        errorIfEmpty(map.get("syncNewOrOldVitalSign"), "患者标识内容不能为空");
        String syncNewOrOldVitalSign = (String) map.get("syncNewOrOldVitalSign");
        if (!StringUtils.equals(syncNewOrOldVitalSign, "true") && !StringUtils.equals(syncNewOrOldVitalSign, "false"))
            return new HttpResult(500, "标识状态错误");
        List<Patient> patientList = patientDao.queryOldPatientByVisitTime(map);
        errorIfEmpty(patientList, "患者列表不存在");
        patientList.forEach(patient -> {
            patient.setSyncNewOrOldVitalSign(syncNewOrOldVitalSign);
            update(patient);
        });
        return new HttpResult(200, "患者新旧表单标识修改成功");
    }

    public Map<String, Object> getOutAndInTotal(Map<String, Object> map) {
        return patientDao.getOutAndInTotal(map);
    }

    public HttpResult updateExitBed(Map<String, Object> param) {
        errorIfEmpty(param.get("patientId"), "请选择患者");
        int update = patientDao.updateExitBed(param);
        if(update > 0){
            return new HttpResult(200, "更新成功");
        } else {
            return new HttpResult(500, "更新失败");
        }
    }

    public HttpResult updateFlag(Map<String, Object> param) {
        errorIfEmpty(param.get("patientId"), "请选择患者");
        errorIfEmpty(param.get("flag"), "请选择患者状态");
        patientDao.updateFlag(param);
        return new HttpResult(200, "更新成功");
    }
}
